package com.lightkits.wms.domain.purchasereceive.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.FndItemBase;
import com.lightkits.common.db.entity.FndOrganizationBase;
import com.lightkits.common.db.entity.FndWmMoveTypeBase;
import com.lightkits.common.db.entity.FndWorker;
import com.lightkits.common.db.entity.ScmPoHeader;
import com.lightkits.common.db.entity.ScmPoLine;
import com.lightkits.common.db.entity.ScmPoTrack;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.framework.soa.client.id.GetGlobalIDRequestType;
import com.lightkits.framework.soa.client.id.GetGlobalIDResponseType;
import com.lightkits.framework.soa.client.id.IDServiceClient;
import com.lightkits.wms.database.dao.WmsWarehouseMapper;
import com.lightkits.wms.database.model.KVCodeModel;
import com.lightkits.wms.domain.deliveryticket.service.SaveTicketHeadDomain;
import com.lightkits.wms.domain.deliveryticket.service.SaveTicketLineDomain;
import com.lightkits.wms.domain.purchasereceive.model.TagModel;
import com.lightkits.wms.domain.purchasereceive.repo.ScmPoHeadService;
import com.lightkits.wms.domain.purchasereceive.repo.ScmPoLineService;
import com.lightkits.wms.domain.purchasereceive.repo.ScmPoTrackService;
import com.lightkits.wms.domain.purchasereceive.service.CreateParamsDomain;
import com.lightkits.wms.domain.purchasereceive.service.CreatePoParamsDomain;
import com.lightkits.wms.domain.purchasereceive.service.CreatePurchaseOrderDomain;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.stocktransfer.service.impl.SubStockTransferDomainImpl;
import com.lightkits.wms.domain.tagservice.UseTagParamsService;
import com.lightkits.wms.dto.deliveryticket.models.TicketHeadDTO;
import com.lightkits.wms.dto.deliveryticket.models.TicketLineDTO;
import com.lightkits.wms.dto.purchasereceive.models.SavePoParamsDTO;
import com.lightkits.wms.dto.tagservice.model.TagViewDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * CreatePurchaseOrderDomainImpl
 *
 * @author jing.wei@hand-china.com
 * Created on 2019/4/26 14:39
 */
@Service
public class CreatePurchaseOrderDomainImpl implements CreatePurchaseOrderDomain {
    private final CreatePoParamsDomain createPoParamsDomain;
    private final ScmPoHeadService scmPoHeadService;
    private final ScmPoLineService scmPoLineService;
    private final ScmPoTrackService scmPoTrackService;
    private final IDServiceClient idAdapterService;
    private static final Logger LOGGER = LoggerFactory.getLogger(SubStockTransferDomainImpl.class);
    private final CreateParamsDomain createParamsDomain;
    private final BdEventService bdEventService;
    private final BdEventRecordService bdEventRecordService;
    private final SaveTicketHeadDomain saveTicketHeadDomain;
    private final SaveTicketLineDomain saveTicketLineDomain;
    private final WmsWarehouseMapper wmsWarehouseMapper;
    private final UseTagParamsService useTagParamsService;

    @Autowired
    public CreatePurchaseOrderDomainImpl(CreatePoParamsDomain createPoParamsDomain, ScmPoHeadService scmPoHeadService, ScmPoLineService scmPoLineService, ScmPoTrackService scmPoTrackService, IDServiceClient idAdapterService, CreateParamsDomain createParamsDomain, BdEventService bdEventService, BdEventRecordService bdEventRecordService, SaveTicketHeadDomain saveTicketHeadDomain, SaveTicketLineDomain saveTicketLineDomain, WmsWarehouseMapper wmsWarehouseMapper, UseTagParamsService useTagParamsService) {
        this.createPoParamsDomain = createPoParamsDomain;
        this.scmPoHeadService = scmPoHeadService;
        this.scmPoLineService = scmPoLineService;
        this.scmPoTrackService = scmPoTrackService;
        this.idAdapterService = idAdapterService;
        this.createParamsDomain = createParamsDomain;
        this.bdEventService = bdEventService;
        this.bdEventRecordService = bdEventRecordService;
        this.saveTicketHeadDomain = saveTicketHeadDomain;
        this.saveTicketLineDomain = saveTicketLineDomain;
        this.wmsWarehouseMapper = wmsWarehouseMapper;
        this.useTagParamsService = useTagParamsService;
    }

    /**
     * 采购订单接收参数校验
     *
     * @param dto 采购订单参数
     * @return
     **/
    private IResult checkParams(SavePoParamsDTO dto) {
        try {
            //采购订单接收参数必输校验
            IntegrityValidator.begin()
                    .validate(dto.getPoId(), "Purchase Order Id")
                    .validate(dto.getPoLineId(), "Purchase Order Line Id")
                    .validate(dto.getItemId(), "Item Id")
                    .validate(dto.getEventRequestId(), "Event Request Id")
                    .validate(dto.getMoveTypeCode(), "Move Type Code")
                    .validate(dto.getReceiveQty(), "Receiver Quantity")
                    .validate(dto.getReceiveWorker(), "Receiver Worker Id");

            //采购订单的数字有效性校验
            Pattern pattern = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");

            String regex = "^[a-z0-9A-Z]+$";
            if (!ObjectUtil.isNullOrEmpty(dto.getLotCode()) && !dto.getLotCode().matches(regex)) {
                throw new LightKitsBizException(" the lot must be number or Letter");
            }
            if (!ObjectUtil.isNullOrEmpty(dto.getInventoryQty())) {
                if (!pattern.matcher(dto.getInventoryQty()).matches()) {
                    return IResult.fail("The Inventory Quantity is invalid");
                }
            }

            if (!ObjectUtil.isNullOrEmpty(dto.getReceiveQty())) {
                if (!pattern.matcher(dto.getReceiveQty()).matches()) {
                    return IResult.fail("The Receive Quantity is invalid");
                }
            }
            if (!ObjectUtil.isNullOrEmpty(dto.getQcNgQty())) {
                if (!pattern.matcher(dto.getQcNgQty()).matches()) {
                    return IResult.fail("The QcNg Quantity is invalid");
                }
            }

            if (!ObjectUtil.isNullOrEmpty(dto.getReturnQty())) {
                if (!pattern.matcher(dto.getReturnQty()).matches()) {
                    return IResult.fail("The Return Quantity is invalid");
                }
            }

        } catch (LightKitsBizException e) {
            return e.result();
        }
        return IResult.success();
    }

    /**
     * 采购订单接收
     *
     * @param dto 采购订单接收参数
     * @return
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult receivePo(SavePoParamsDTO dto) {

        //判断是否具有请求ID
        if (ObjectUtil.isEmpty(dto.getEventRequestId()) || dto.getEventRequestId() == 0) {
            GetGlobalIDRequestType idRequest = new GetGlobalIDRequestType();
            idRequest.setCount(1);
            GetGlobalIDResponseType idResponse = idAdapterService.getGlobalId(idRequest);
            Iterator<Long> sfIds = idResponse.getIds().iterator();
            dto.setEventRequestId(sfIds.next());
        }
        IResult result = IResult.success();
        try {
            //参数校验
            result = this.checkParams(dto);
            if (!result.isSuccessful()) {
                return result;
            }
            //根据移动类型获取事件编码
            FndWmMoveTypeBase moveTypeBase = new FndWmMoveTypeBase().selectOne(
                    new EntityWrapper()
                            .eq(FndWmMoveTypeBase.MOVE_TYPE_CODE, dto.getMoveTypeCode()));

            //create Event
            BdEvent bdEvent = createParamsDomain.createEvent(dto, moveTypeBase.getEventTypeId());
            Boolean eventFlag = bdEventService.insert(bdEvent);
            if (!eventFlag) {
                throw new LightKitsBizException("Insert Po Event Failed");
            }
            //create PoLine
            CheckResult checkResult = createPoParamsDomain.createLines(dto);
            List<BdEventRecord> bdEventRecords;
            List<ScmPoTrack> poTracks = new ArrayList<>();
            if (checkResult.isSuccessful()) {
                //修改采购订单行
                ScmPoLine line = (ScmPoLine) checkResult.getData();
                boolean updatePoLineFlag = scmPoLineService.updateById(line);
                if (!updatePoLineFlag) {
                    throw new LightKitsBizException("Update Po Line error.");
                }
                //获取采购订单行的快照
                bdEventRecords = this.getEvetRecord(line.take("RECORDS"), bdEvent.getId(), line);
                //获取采购订单追踪根据接受数量
                if (!ObjectUtil.isEmpty(line.getRecievedQty())) {
                    List<Object> tracks = line.take("PO_TRACK");
                    try {
                        for (Object object : tracks) {
                            if (object.getClass().equals(ScmPoTrack.class)) {
                                ScmPoTrack track = (ScmPoTrack) object;
                                poTracks.add(track);
                            }
                        }
                    } catch (Exception e) {
                        LOGGER.error("Create Po Track Failed", e);
                        throw new LightKitsBizException(e);
                    }
                    //插入采购订单追踪
                    boolean insertPoTrack = scmPoTrackService.insertBatch(poTracks);
                    if (!insertPoTrack) {
                        throw new LightKitsBizException("Insert Po Track error.");
                    }
                }
                //插入快照
                boolean insertHeadRecordFlag = bdEventRecordService.insertBatch(bdEventRecords);
                if (!insertHeadRecordFlag) {
                    throw new LightKitsBizException("Insert Po Line Record error.");
                }

            } else {
                throw new LightKitsBizException("Create Po Line Failed");
            }
            //创建送货单头
            checkResult = createPoParamsDomain.createTicketHead(dto);
            if (!checkResult.isSuccessful() && checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            TicketHeadDTO head = (TicketHeadDTO) checkResult.getData();
            head.setParentEventId(bdEvent.getId());
            checkResult = saveTicketHeadDomain.saveTicketHead(head);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            //创建送货单行
            Map<String, String> delivertTicketMap = (Map<String, String>) checkResult.getData();
            String ticketId = delivertTicketMap.get("ticketHeadId");
            checkResult = createPoParamsDomain.createTicketLine(dto);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            TicketLineDTO ticketLine = (TicketLineDTO) checkResult.getData();
            List<TicketLineDTO> ticketLines = new ArrayList<>();
            ticketLines.add(ticketLine);
            result = saveTicketLineDomain.saveTicketLine(ticketLines, ticketId, bdEvent.getId().toString());
            if (!result.isSuccessful()) {
                throw new LightKitsBizException(result.getMessage());
            }
            //create Tag

            //判断该组织下是否维护条码类型
            FndOrganizationBase orgBase = new FndOrganizationBase().selectById(dto.getOrgId());
            List<KVCodeModel> models = wmsWarehouseMapper.querySysCode("WM_PO_RECIEVE_TAG_PRINT", orgBase.getOrganizationCode(), "");
            //根据维护的条码类型创建条码
            if (!ObjectUtil.isNullOrEmpty(models) && models.size() == 1) {
                List<TagViewDto> tagViewDtos = createParamsDomain.createTagParams(dto,models.get(0).getValue(),
                        bdEvent);

//                if (models.get(0).getValue().equals("1U1S")) {
//                    for (int i = 0; i < Integer.valueOf(ticketLine.getReceiveQty()); i++) {
//                        //创建并生成1U1S类型条码
//
//                        checkResult = createParamsDomain.createTagParams(dto, "1U1S", bdEvent, "1");
//                        if (!checkResult.isSuccessful() && checkResult.getData() == null) {
//                            throw new LightKitsBizException(checkResult.getMessage());
//                        }
//                        TagViewDto tagViewDto = (TagViewDto) checkResult.getData();
//                        tagViewDtos.add(tagViewDto);
//
//                    }
//                }
//
//                if (models.get(0).equals("1U1T")) {
//                    //创建并生成1U1T类型条码
//                    checkResult = createParamsDomain.createTagParams(dto, "1U1T", bdEvent, dto.getReceiveQty());
//                    if (!checkResult.isSuccessful() && checkResult.getData() == null) {
//                        throw new LightKitsBizException(checkResult.getMessage());
//                    }
//                    TagViewDto tagViewDto = (TagViewDto) checkResult.getData();
//                    tagViewDtos.add(tagViewDto);
//                }
                if (!ObjectUtil.isNullOrEmpty(tagViewDtos)) {
                    result = useTagParamsService.insertValue(tagViewDtos);
                    if (!result.isSuccessful()) {
                        throw new LightKitsBizException(result.getMessage());
                    }
                }

            }

            //判断时候接收完毕，接收完毕后修改采购订单头状态
            if (this.checkQty(dto).isSuccessful()) {
                //创建采购订单头
                checkResult = createPoParamsDomain.createHead(dto.getPoId());
                if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                    throw new LightKitsBizException(checkResult.getMessage());
                }
                ScmPoHeader header = (ScmPoHeader) checkResult.getData();
                boolean poHeaderFlag = scmPoHeadService.updateById(header);
                if (!poHeaderFlag) {
                    throw new LightKitsBizException("Update Po Head Error");
                }
                String actionRecords = "已完成";
                ScmPoTrack poTrack = createParamsDomain.createPoTrack(dto, actionRecords);
                boolean poHeaderTrackFlag = scmPoTrackService.insert(poTrack);
                if (!poHeaderTrackFlag) {
                    throw new LightKitsBizException("Update Po Head Track Error");
                }
            }

        } catch (Exception e) {
            LOGGER.error("Receive Purchare Order error", e);
            throw new LightKitsBizException(e);
        }
        return result;

    }

    /**
     * @param records 快照对象
     * @param snap    记录保存
     * @param eventId 事件ID
     * @return
     **/
    private List<BdEventRecord> getEvetRecord(List<Object> records, Long eventId, Object snap) {
        List<BdEventRecord> bdEventRecords = new ArrayList<>();
        try {
            for (Object object : records) {
                if (object.getClass().equals(BdEventRecord.class)) {
                    BdEventRecord record = (BdEventRecord) object;
                    record.setEventId(eventId);
                    if (snap != null) {
                        record.setSnapshotRecord(JsonUtil.toString(object));

                    }
                    bdEventRecords.add(record);
                }
            }
        } catch (Exception e) {
            LOGGER.error("getEventRecord.error", e);
            throw new LightKitsBizException(e);
        }
        return bdEventRecords;
    }

    /**
     * 判断该次接受是否达到需求数量
     *
     * @param dto
     * @return
     **/

    private IResult checkQty(SavePoParamsDTO dto) {
        IResult result = IResult.success();
        try {
            List<ScmPoLine> poLines = new ScmPoLine().selectList(new EntityWrapper()
                    .eq(ScmPoLine.PO_HEADER_ID, dto.getPoId()));
            poLines.forEach(line -> {
                line.setRecievedQty(ObjectUtil.isEmpty(line.getRecievedQty())
                        ? new BigDecimal(0) : line.getRecievedQty());
                line.setDemandQty(ObjectUtil.isEmpty(line.getDemandQty())
                        ? new BigDecimal(0) : line.getDemandQty());
                if (line.getRecievedQty().compareTo(line.getDemandQty()) < 0) {
                    result.setSuccessful(false);
                }
            });
        } catch (Exception e) {
            LOGGER.error("check Qty.error", e);
            throw new LightKitsBizException(e);
        }
        return result;
    }
}
